package com.maixy.studyonlineapi.apis;


import com.alibaba.fastjson.JSON;
import com.maixy.studyonlineapi.exceptions.ApiException;
import com.maixy.studyonlineapi.exceptions.TipException;
import com.maixy.studyonlineapi.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @Description TODO
 * @Date 2020/7/27 0:04
 * @Created by maixy
 */
@Slf4j
@CrossOrigin(origins = "*", allowedHeaders = "*", methods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.OPTIONS}, allowCredentials = "true")
public class ApiController {

    @RequestMapping(value = "/{methodName}", produces = {"application/json;charset=UTF-8"}, method = RequestMethod.POST)
    public Object invoke(@PathVariable String methodName, @RequestBody String requestBody, HttpServletRequest req, HttpServletResponse res) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        String controllerClassName = this.getClass().getName();
        if ("favicon".equals(methodName)) {
            log.info("H5 call favicon request, break.");
            throw new ApiException();
        }
        ApiResponse response;
        String id = null;
        ApiRequest request;
        log.info("ip={}, class={}, method={}, request={}", getRemoteIP(req), controllerClassName, methodName, requestBody);
        request = this.buildRequest(requestBody, req);
        if (StringUtils.isEmpty(requestBody)) {
            log.error("JSON error, request body is blank, class={}, method={}",
                    controllerClassName, methodName);
            throw new ApiException();
        }
        Object obj = this;
        Method method = this.getClass().getMethod(methodName, ApiRequest.class);
        //权限认证
        Privilege privilege = method.getAnnotation(Privilege.class);
        if (null != privilege && "login".equals(privilege.type())) {
            JwtUtils.verityToken(request.getUser().getSessionId());
        }

        //request = checkPage(request);
        //实际处理
        response = fillResponse((ApiResponse) method.invoke(obj, request), id);

        if (request != null) {
            log.info("Response is {}, class={}, method={}", JSON.toJSONString(response), controllerClassName, methodName);
        } else {
            log.info("request is null !  Response is {}, class={}, method={}", JSON.toJSONString(response), controllerClassName, methodName);
        }

        return response;
    }


    /**
     * 从HttpServletRequest中获取远程IP
     */
    private String getRemoteIP(HttpServletRequest request) {

        String ip = request.getHeader("X-Real-IP");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("x-forwarded-for");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    /**
     * 初始化ApiRequest
     *
     * @param req HttpServletRequest
     * @return ApiRequest
     */
    private ApiRequest buildRequest(String requestBody, HttpServletRequest req) {
        ApiRequest request;
        try {
            //body
            request = JSON.parseObject(requestBody, ApiRequest.class);
        } catch (Exception e) {
            log.error("初始化ApiRequest异常 requestBody:{} req:{}", requestBody, JSON.toJSONString(req), e);
            throw new TipException();
        }
        return request;
    }

    /**
     * 填充response数据
     *
     * @param response response
     * @param id       id
     * @return ApiResponse
     */
    private ApiResponse fillResponse(ApiResponse response, String id) {
        return response;
    }
}
